home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 9 / Night Owl CD-ROM (NOPV9) (Night Owl Publisher) (1993).ISO / 009a / tde221.zip / WINDOW.C < prev    next >
C/C++ Source or Header  |  1993-04-01  |  39KB  |  1,247 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - window module
  10.  * Purpose: This file contains the code associated with opening and sizing
  11.  *           windows, and also displaying the help window.
  12.  * File:    window.c
  13.  * Author:  Douglas Thomson
  14.  * System:  this file is intended to be system-independent
  15.  * Date:    October 12, 1989
  16.  */
  17. /*********************  end of original comments   ********************/
  18.  
  19.  
  20. /*
  21.  * The window routines have been EXTENSIVELY rewritten.  Some routines were
  22.  * changed so only one logical function is carried out, eg. 'initialize_window'.
  23.  * I like the Microsoft way of resizing windows - just press the up and down
  24.  * arrows to adjust the window to desired size.  I also like pressing one key
  25.  * to change windows.  All of which are implemented in TDE.
  26.  *
  27.  * In TDE, version 1.4, I added support for vertical windows.
  28.  *
  29.  * New editor name:  TDE, the Thomson-Davis Editor.
  30.  * Author:           Frank Davis
  31.  * Date:             June 5, 1991, version 1.0
  32.  * Date:             July 29, 1991, version 1.1
  33.  * Date:             October 5, 1991, version 1.2
  34.  * Date:             January 20, 1992, version 1.3
  35.  * Date:             February 17, 1992, version 1.4
  36.  * Date:             April 1, 1992, version 1.5
  37.  * Date:             June 5, 1992, version 2.0
  38.  * Date:             October 31, 1992, version 2.1
  39.  * Date:             April 1, 1993, version 2.2
  40.  *
  41.  * This modification of Douglas Thomson's code is released into the
  42.  * public domain, Frank Davis.  You may distribute it freely.
  43.  */
  44.  
  45. #include "tdestr.h"
  46. #include "common.h"
  47. #include "define.h"
  48. #include "tdefunc.h"
  49.  
  50.  
  51. /*
  52.  * Name:    initialize_window
  53.  * Purpose: To open a new window
  54.  * Date:    June 5, 1991
  55.  * Returns: OK if window opened successfully
  56.  *          ERROR if anything went wrong
  57.  * Notes:   If this is first window, then set up as normal displayed window;
  58.  *          otherwise, make the present window invisible and open a new
  59.  *          window in the same screen location as the old one.
  60.  */
  61. int  initialize_window( void )
  62. {
  63. int  top;
  64. int  bottom;
  65. int  start_col;
  66. int  end_col;
  67. WINDOW *wp;        /* used for scanning windows */
  68. WINDOW *window;
  69. register file_infos *fp;     /* used for scanning files */
  70. register int rc;
  71. line_list_ptr ll;
  72. line_list_ptr temp_ll;
  73.  
  74.    rc = OK;
  75.    window = g_status.current_window;
  76.    fp = g_status.current_file;
  77.    if (window == NULL) {
  78.       /*
  79.        * special case if this is the first window on screen.
  80.        */
  81.       top = start_col = 0;
  82.       bottom  = g_display.nlines;
  83.       end_col = g_display.ncols - 1;
  84.    } else {
  85.       /*
  86.        * else put the new window in same place as current window.
  87.        *  make current window invisible.  new window becomes current window.
  88.        */
  89.       top       = window->top_line - 1;
  90.       bottom    = window->bottom_line;
  91.       start_col = window->start_col;
  92.       end_col   = window->end_col;
  93.    }
  94.  
  95.    assert( top < bottom );
  96.    assert( start_col < end_col );
  97.    assert( fp != NULL );
  98.  
  99.    if (create_window( &wp, top, bottom, start_col, end_col, fp ) == ERROR) {
  100.       /*
  101.        * out of memory
  102.        */
  103.       error( WARNING, bottom, main4 );
  104.  
  105.       /*
  106.        * This is a real nuisance. We had room for the file and the
  107.        *  file structure, but not enough for the window as well.
  108.        * Now we must free all the memory that has already been
  109.        *  allocated.
  110.        */
  111.       if (fp->ref_count == 0) {
  112.  
  113.          /*
  114.           * remove fp from file pointer list.
  115.           */
  116.          if (fp->prev != NULL)
  117.             fp->prev->next = fp->next;
  118.          else
  119.             g_status.file_list = fp->next;
  120.  
  121.          if (fp->next != NULL)
  122.             fp->next->prev = fp->prev;
  123.  
  124.          /*
  125.           * free the undo stack, line pointers, and linked list.
  126.           */
  127.  
  128.          ll = fp->undo_top;
  129.          while (ll != NULL) {
  130.             temp_ll = ll->next;
  131.             if (ll->line != NULL)
  132.                my_free( ll->line );
  133.             my_free( ll );
  134.             ll = temp_ll;
  135.          }
  136.  
  137.          ll = fp->line_list;
  138.          while (ll != NULL) {
  139.             temp_ll = ll->next;
  140.             if (ll->line != NULL)
  141.                my_free( ll->line );
  142.             my_free( ll );
  143.             ll = temp_ll;
  144.          }
  145.  
  146. #if defined( __MSC__ )
  147.          _fheapmin( );
  148. #endif
  149.  
  150.          free( fp );
  151.          wp = g_status.current_window;
  152.          if (wp != NULL && wp->visible)
  153.             g_status.current_file = wp->file_info;
  154.          else
  155.             g_status.stop = TRUE;
  156.       }
  157.       rc = ERROR;
  158.    }
  159.  
  160.    if (rc != ERROR) {
  161.       /*
  162.        * set up the new cursor position as appropriate
  163.        */
  164.       wp->ccol = wp->start_col;
  165.       wp->rcol = wp->bcol = 0;
  166.       wp->rline = 1L;
  167.       wp->ll    = fp->line_list;
  168.       wp->visible = TRUE;
  169.       wp->letter = fp->next_letter++;
  170.       if (window != NULL)
  171.          window->visible = FALSE;
  172.  
  173.       /*
  174.        * the new window becomes the current window.
  175.        */
  176.       g_status.current_window = wp;
  177.    }
  178.    return( rc );
  179. }
  180.  
  181.  
  182. /*
  183.  * Name:    next_window
  184.  * Purpose: To move to the next visible window.
  185.  * Date:    June 5, 1991
  186.  * Passed:  window:  pointer to current window
  187.  * Notes:   Start with current window.  If next window exists then go to it
  188.  *           else go to the first (top) window on screen.
  189.  *          When I added vertical windows, finding the "correct" next
  190.  *           window became extremely, unnecessarily, unmanageably complicated.
  191.  *           let's just use a simple procedure to find the first available,
  192.  *           visible, next window.
  193.  */
  194. int  next_window( WINDOW *window )
  195. {
  196. register WINDOW *wp;
  197. int  change;
  198.  
  199.    if (window != NULL) {
  200.       change = FALSE;
  201.       /*
  202.        * start with current window and look for first next
  203.        *  visible window
  204.        */
  205.       wp = window->next;
  206.       while (wp != NULL) {
  207.          if (wp->visible) {
  208.             change = TRUE;
  209.             break;
  210.          }
  211.          wp = wp->next;
  212.       }
  213.  
  214.       /*
  215.        * if we haven't found a visible window yet, go to the beginning of
  216.        *  the list until we find a visible window.
  217.        */
  218.       if (!change) {
  219.          wp = g_status.window_list;
  220.          while (wp != window) {
  221.             if (wp->visible) {
  222.                change = TRUE;
  223.                break;
  224.             }
  225.             wp = wp->next;
  226.          }
  227.       }
  228.       if (change == TRUE) {
  229.          entab_linebuff( );
  230.          un_copy_line( window->ll, window, TRUE );
  231.          g_status.current_window = wp;
  232.          g_status.current_file = wp->file_info;
  233.       }
  234.    }
  235.    return( OK );
  236. }
  237.  
  238.  
  239. /*
  240.  * Name:    prev_window
  241.  * Purpose: To move to the previous visible window.
  242.  * Date:    June 5, 1991
  243.  * Passed:  window:  pointer to current window
  244.  * Notes:   Start with current window.  If previous window exists then go to
  245.  *           it else go to the last (bottom) window on screen.  Opposite of
  246.  *           next_window.
  247.  *          when I added vertical windows, finding the "correct" previous
  248.  *           window became extremely, unnecessarily, unmanageably complicated.
  249.  *           let's just use a simple procedure to find the first available,
  250.  *           visible, previous window.
  251.  */
  252. int  prev_window( WINDOW *window )
  253. {
  254. register WINDOW *wp;
  255. int  change;
  256.  
  257.    if (window != NULL) {
  258.       change = FALSE;
  259.  
  260.       /*
  261.        * start with current window and look for first previous
  262.        *  visible window
  263.        */
  264.       wp = window->prev;
  265.       while (wp != NULL) {
  266.          if (wp->visible) {
  267.             change = TRUE;
  268.             break;
  269.          }
  270.          wp = wp->prev;
  271.       }
  272.  
  273.       /*
  274.        * if we haven't found a visible window yet, go to the end of
  275.        *  the list and work backwards until we find a visible window.
  276.        */
  277.       if (!change) {
  278.          wp = window->next;
  279.          if (wp != NULL) {
  280.             while (wp->next != NULL)
  281.                wp = wp->next;
  282.             while (wp != window) {
  283.                if (wp->visible) {
  284.                   change = TRUE;
  285.                   break;
  286.                }
  287.                wp = wp->prev;
  288.             }
  289.          }
  290.       }
  291.       if (change == TRUE) {
  292.          entab_linebuff( );
  293.          un_copy_line( window->ll, window, TRUE );
  294.          g_status.current_window = wp;
  295.          g_status.current_file = wp->file_info;
  296.       }
  297.    }
  298.    return( OK );
  299. }
  300.  
  301.  
  302. /*
  303.  * Name:    split_horizontal
  304.  * Purpose: To split screen horizontally at the cursor.
  305.  * Date:    June 5, 1991
  306.  * Passed:  window:  pointer to current window
  307.  * Notes:   split the screen horizontally at the cursor position.
  308.  */
  309. int  split_horizontal( WINDOW *window )
  310. {
  311. register WINDOW *wp;
  312. register WINDOW *win;   /* register pointer for window */
  313. WINDOW *temp;
  314. file_infos *file;       /* file structure for file belonging to new window */
  315. int  rc;
  316.  
  317.    rc = OK;
  318.    win = window;
  319.    if ( win != NULL) {
  320.  
  321.       /*
  322.        * check that there is room for the window
  323.        */
  324.       if (win->bottom_line - win->cline < 2) {
  325.          /*
  326.           * move cursor up first
  327.           */
  328.          error( WARNING, win->bottom_line, win1 );
  329.          rc = ERROR;
  330.       } else {
  331.          file = win->file_info;
  332.  
  333.          assert( file != NULL );
  334.  
  335.          if (create_window( &temp, win->cline+1, win->bottom_line,
  336.                             win->start_col, win->end_col, file ) == ERROR) {
  337.             /*
  338.              * out of memory
  339.              */
  340.             error( WARNING, win->bottom_line, main4 );
  341.             rc = ERROR;
  342.          }
  343.          if (rc == OK  &&  temp != NULL) {
  344.             entab_linebuff( );
  345.             un_copy_line( win->ll, win, TRUE );
  346.             wp = temp;
  347.             /*
  348.              * record that the current window has lost some lines from
  349.              *  the bottom for the new window, and adjust its page size
  350.              *  etc accordingly.
  351.              */
  352.             win->bottom_line = win->cline;
  353.             setup_window( win );
  354.             display_current_window( win );
  355.  
  356.             /*
  357.              * set up the new cursor position as appropriate
  358.              */
  359.             wp->rcol = win->rcol;
  360.             wp->ccol = win->ccol;
  361.             wp->bcol = win->bcol;
  362.             wp->rline = win->rline;
  363.             wp->bin_offset = win->bin_offset;
  364.             wp->ll    = win->ll;
  365.             wp->cline = wp->cline + win->cline - (win->top_line + win->ruler);
  366.             if (wp->cline > wp->bottom_line)
  367.                wp->cline = wp->bottom_line;
  368.             wp->visible = TRUE;
  369.             wp->vertical = win->vertical;
  370.             wp->letter = file->next_letter++;
  371.             wp->ruler  = mode.ruler;
  372.  
  373.             /*
  374.              * the new window becomes the current window.
  375.              */
  376.             g_status.current_window = wp;
  377.  
  378.             show_window_count( g_status.window_count );
  379.             show_window_header( wp );
  380.             display_current_window( wp );
  381.             if (wp->vertical)
  382.                show_vertical_separator( wp );
  383.             make_ruler( wp );
  384.             show_ruler( wp );
  385.             rc = OK;
  386.          }
  387.       }
  388.    } else
  389.       rc = ERROR;
  390.    return( rc );
  391. }
  392.  
  393.  
  394. /*
  395.  * Name:    split_vertical
  396.  * Purpose: To split screen vertically at the cursor.
  397.  * Date:    June 5, 1991
  398.  * Passed:  window:  pointer to current window
  399.  * Notes:   split the screen vertically at the cursor position.
  400.  */
  401. int  split_vertical( WINDOW *window )
  402. {
  403. register WINDOW *wp;
  404. register WINDOW *win;   /* register pointer for window */
  405. WINDOW *temp;
  406. file_infos *file;       /* file structure for file belonging to new window */
  407. int  rc;
  408.  
  409.    rc = OK;
  410.    win = window;
  411.    if (win != NULL) {
  412.  
  413.       /*
  414.        * check that there is room for the window
  415.        */
  416.       if (win->start_col + 15 > win->ccol) {
  417.          /*
  418.           * move cursor right first
  419.           */
  420.          error( WARNING, win->bottom_line, win2 );
  421.          rc = ERROR;
  422.       } else if (win->end_col - 15 < win->ccol) {
  423.          /*
  424.           * move cursor left first
  425.           */
  426.          error( WARNING, win->bottom_line, win3 );
  427.          rc = ERROR;
  428.       } else {
  429.          file = win->file_info;
  430.  
  431.          assert( file != NULL );
  432.  
  433.          if (create_window( &temp, win->top_line-1, win->bottom_line,
  434.                             win->ccol+1, win->end_col, file ) == ERROR) {
  435.             /*
  436.              * out of memory
  437.              */
  438.             error( WARNING, win->bottom_line, main4 );
  439.             rc = ERROR;
  440.          }
  441.  
  442.          if (rc == OK  &&  temp != NULL) {
  443.             entab_linebuff( );
  444.             un_copy_line( win->ll, win, TRUE );
  445.             wp = temp;
  446.  
  447.             /*
  448.              * record that the current window has lost some columns from
  449.              *  the window to the left for the new window
  450.              */
  451.             win->ccol = win->end_col = win->ccol - 1;
  452.             win->rcol--;
  453.             win->vertical = TRUE;
  454.             show_window_header( win );
  455.             show_vertical_separator( win );
  456.             display_current_window( win );
  457.             make_ruler( win );
  458.             show_ruler( win );
  459.             show_ruler_pointer( win );
  460.  
  461.             /*
  462.              * set up the new cursor position as appropriate
  463.              */
  464.             wp->rcol = win->rcol;
  465.             wp->ccol = wp->start_col + win->ccol - win->start_col;
  466.             if (wp->ccol > wp->end_col)
  467.                wp->ccol = wp->end_col;
  468.             wp->bcol  = win->bcol;
  469.             wp->rline = win->rline;
  470.             wp->bin_offset = win->bin_offset;
  471.             wp->ll       = win->ll;
  472.             wp->cline    = win->cline;
  473.             wp->visible  = TRUE;
  474.             wp->vertical = TRUE;
  475.             wp->letter   = file->next_letter++;
  476.             wp->ruler    = mode.ruler;
  477.  
  478.             /*
  479.              * the new window becomes the current window.
  480.              */
  481.             g_status.current_window = wp;
  482.  
  483.             check_virtual_col( wp, wp->rcol, wp->ccol );
  484.             wp->file_info->dirty = FALSE;
  485.             show_window_count( g_status.window_count );
  486.             show_window_header( wp );
  487.             display_current_window( wp );
  488.             make_ruler( wp );
  489.             show_ruler( wp );
  490.          }
  491.       }
  492.    } else
  493.       rc = ERROR;
  494.    return( rc );
  495. }
  496.  
  497.  
  498. /*
  499.  * Name:    show_vertical_separator
  500.  * Purpose: To separate vertical screens
  501.  * Date:    June 5, 1991
  502.  * Passed:  window:  pointer to current window
  503.  */
  504. void show_vertical_separator( WINDOW *window )
  505. {
  506. int  i;
  507. int  line;
  508. int  col;
  509.  
  510.    line = window->top_line - 1;
  511.    col  = window->end_col + 1;
  512.    if (col < g_display.ncols - 1) {
  513.       i = window->bottom_line - line;
  514.  
  515.       assert( i <= g_display.nlines );
  516.  
  517.       while (i-- >= 0)
  518.          c_output( VERTICAL_CHAR, col, line++, g_display.head_color );
  519.    }
  520. }
  521.  
  522.  
  523. /*
  524.  * Name:    size_window
  525.  * Purpose: To change the size of the current and one other window.
  526.  * Date:    June 5, 1991
  527.  * Passed:  window:  pointer to current window
  528.  * Notes:   Use the Up and Down arrow keys to make the current window
  529.  *           bigger or smaller.  The window above will either grow
  530.  *           or contract accordingly.
  531.  */
  532. int  size_window( WINDOW *window )
  533. {
  534. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  535. int  func;
  536. int  c;
  537. int  resize;
  538. int  show_above_ruler;
  539. int  old_bottom_line;
  540. int  old_top_line;
  541. int  new_bottom_line;
  542. int  new_top_line;
  543. register WINDOW *above;
  544. register WINDOW *win;
  545.  
  546.    win = window;
  547.    if (win->top_line != 1 && !win->vertical) {
  548.       entab_linebuff( );
  549.       un_copy_line( win->ll, win, TRUE );
  550.       save_screen_line( 0, win->bottom_line, line_buff );
  551.  
  552.       /*
  553.        * press up or down to change window size
  554.        */
  555.       set_prompt( win4, win->bottom_line );
  556.  
  557.       /*
  558.        * resizing only affects current window and above visible window
  559.        */
  560.       above = g_status.window_list;
  561.       while (above->bottom_line + 2 != win->top_line || !above->visible)
  562.          above = above->next;
  563.       if (above->vertical)
  564.          /*
  565.           * cannot resize vertical window
  566.           */
  567.          error( WARNING, win->bottom_line, win5 );
  568.       else {
  569.          old_top_line = win->top_line;
  570.          old_bottom_line = above->bottom_line;
  571.          show_above_ruler = FALSE;
  572.          for (func=0; func != AbortCommand && func != Rturn; ) {
  573.  
  574.             /*
  575.              * If user has redined the ESC and Return keys, make them Rturn and
  576.              *  AbortCommand in this function.
  577.              */
  578.             c = getkey( );
  579.             func = getfunc( c );
  580.             if (c == RTURN || func == NextLine || func == BegNextLine)
  581.                func = Rturn;
  582.             else if (c == ESC)
  583.                func = AbortCommand;
  584.             resize = FALSE;
  585.  
  586.             /*
  587.              * if LineUp, make current window top line grow and bottom line
  588.              *  of above window shrink.  if window movement covers up current
  589.              *  line of window then we must adjust logical line and real line.
  590.              */
  591.             if (func == LineUp) {
  592.                if (above->bottom_line > above->top_line + above->ruler) {
  593.                   if (win->rline == (win->cline - (win->top_line+win->ruler-1)))
  594.                      --win->cline;
  595.                   --win->top_line;
  596.                   if (above->cline == above->bottom_line)
  597.                      --above->cline;
  598.                   --above->bottom_line;
  599.                   resize = TRUE;
  600.                   if (mode.ruler) {
  601.                      if (win->ruler == FALSE) {
  602.                         if (win->cline == win->top_line)
  603.                            ++win->cline;
  604.                         if (win->cline > win->bottom_line)
  605.                            win->cline = win->bottom_line;
  606.                         win->ruler = TRUE;
  607.                      }
  608.                   }
  609.                }
  610.  
  611.             /*
  612.              * if LineDown, make current window top line shrink and bottom line
  613.              *  of above window grow.  if window movement covers up current
  614.              *  line of window then we must adjust logical line and real line.
  615.              */
  616.             } else if (func == LineDown) {
  617.                if (win->bottom_line > win->top_line + win->ruler) {
  618.                   if (win->cline == win->top_line + win->ruler)
  619.                      ++win->cline;
  620.                   ++win->top_line;
  621.                   ++above->bottom_line;
  622.                   resize = TRUE;
  623.                   if (mode.ruler) {
  624.                      if (above->ruler == FALSE) {
  625.                         if (above->cline == above->top_line)
  626.                            ++above->cline;
  627.                         if (above->cline > above->bottom_line)
  628.                            above->cline = above->bottom_line;
  629.                         above->ruler = TRUE;
  630.                         make_ruler( above );
  631.                         show_above_ruler = TRUE;
  632.                      }
  633.                   }
  634.                }
  635.             }
  636.  
  637.             /*
  638.              * if we resize a window, then update window size and current and
  639.              *  real lines if needed.
  640.              */
  641.             if (resize == TRUE) {
  642.                setup_window( above );
  643.                display_current_window( above );
  644.                if (show_above_ruler) {
  645.                   show_ruler( above );
  646.                   show_ruler_pointer( above );
  647.                   show_above_ruler = FALSE;
  648.                }
  649.                setup_window( win );
  650.                show_window_header( win );
  651.                win->ruler = mode.ruler;
  652.                make_ruler( win );
  653.                show_ruler( win );
  654.                show_ruler_pointer( win );
  655.                display_current_window( win );
  656.                save_screen_line( 0, win->bottom_line, line_buff );
  657.  
  658.                /*
  659.                 * press up or down to change window size
  660.                 */
  661.                set_prompt( win4, win->bottom_line );
  662.             }
  663.          }
  664.          new_top_line = win->top_line;
  665.          new_bottom_line = above->bottom_line;
  666.          for (above=g_status.window_list; above != NULL; above=above->next) {
  667.             if (!above->visible) {
  668.                if (above->bottom_line == old_bottom_line) {
  669.                   above->bottom_line = new_bottom_line;
  670.                   if (above->cline < new_bottom_line)
  671.                      above->cline = new_bottom_line;
  672.                   setup_window( above );
  673.                } else if (above->top_line == old_top_line) {
  674.                   above->top_line = new_top_line;
  675.                   if (above->cline < new_top_line)
  676.                      above->cline = new_top_line;
  677.                   if ((long)(above->cline+1L - (above->top_line+above->ruler)) >
  678.                                                                 above->rline)
  679.                      above->cline = (int)above->rline + above->top_line +
  680.                                      above->ruler - 1;
  681.                   setup_window( above );
  682.                }
  683.             }
  684.          }
  685.       }
  686.       restore_screen_line( 0, win->bottom_line, line_buff );
  687.    } else {
  688.      if (win->vertical)
  689.         /*
  690.          * cannot resize vertical window
  691.          */
  692.         error( WARNING, win->bottom_line, win5 );
  693.      else
  694.         /*
  695.          * cannot resize top window
  696.          */
  697.         error( WARNING, win->bottom_line, win6 );
  698.    }
  699.    return( OK );
  700. }
  701.  
  702.  
  703. /*
  704.  * Name:    zoom_window
  705.  * Purpose: To blow-up current window.
  706.  * Date:    September 1, 1991
  707.  * Passed:  window:  pointer to current window
  708.  * Notes:   Make all windows, visible and hidden, full size.
  709.  */
  710. int  zoom_window( WINDOW *window )
  711. {
  712. register WINDOW *wp;
  713.  
  714.    if (window != NULL) {
  715.       entab_linebuff( );
  716.       un_copy_line( window->ll, window, TRUE );
  717.       for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  718.          if (wp != window && wp->visible)
  719.             wp->visible = FALSE;
  720.  
  721.          /*
  722.           * can't diff one window, reset the diff
  723.           */
  724.          diff.defined = FALSE;
  725.          if (wp->top_line != 1)
  726.             wp->cline = wp->cline - (wp->top_line+wp->ruler) + 1;
  727.          wp->top_line = 1;
  728.          wp->bottom_line = g_display.nlines;
  729.          wp->end_col   = g_display.ncols - 1;
  730.          wp->start_col = 0;
  731.          wp->vertical  = FALSE;
  732.          check_virtual_col( wp, wp->rcol, wp->ccol );
  733.          make_ruler( wp );
  734.       }
  735.       redraw_screen( window );
  736.       show_ruler( window );
  737.    }
  738.    return( OK );
  739. }
  740.  
  741.  
  742. /*
  743.  * Name:    next_hidden_window
  744.  * Purpose: To display the window that is "behind" current window.
  745.  * Date:    September 1, 1991
  746.  * Passed:  window:  pointer to current window
  747.  */
  748. int  next_hidden_window( WINDOW *window )
  749. {
  750. int  poof = FALSE;
  751. register WINDOW *wp;
  752.  
  753.    if (window != NULL) {
  754.  
  755.       /*
  756.        * look for next hidden window starting with current window.
  757.        */
  758.       wp = window;
  759.       for (wp=window->next; wp != NULL && !poof; ) {
  760.          if (!wp->visible)
  761.             poof = TRUE;
  762.          else
  763.             wp = wp->next;
  764.       }
  765.  
  766.       /*
  767.        * if we haven't found an invisible window yet, start looking
  768.        *  for a hidden window from the beginning of the window list.
  769.        */
  770.       if (!poof) {
  771.          for (wp=g_status.window_list; wp != NULL && !poof; ) {
  772.             if (!wp->visible)
  773.                poof = TRUE;
  774.             else
  775.                wp = wp->next;
  776.          }
  777.       }
  778.  
  779.       if (poof) {
  780.          entab_linebuff( );
  781.          un_copy_line( window->ll, window, TRUE );
  782.          wp->cline = window->top_line + window->ruler +
  783.                        (wp->cline - (wp->top_line + wp->ruler));
  784.          wp->top_line = window->top_line;
  785.          wp->bottom_line = window->bottom_line;
  786.          wp->start_col = window->start_col;
  787.          wp->end_col   = window->end_col;
  788.          wp->vertical  = window->vertical;
  789.          if (wp->cline < wp->top_line + wp->ruler)
  790.             wp->cline = wp->top_line + wp->ruler;
  791.          if (wp->cline > wp->bottom_line)
  792.             wp->cline = wp->bottom_line;
  793.          if ((wp->cline+1L - (wp->top_line+wp->ruler)) > wp->rline)
  794.             wp->cline = (int)wp->rline + wp->top_line + wp->ruler - 1;
  795.          check_virtual_col( wp, wp->rcol, wp->ccol );
  796.          wp->visible = TRUE;
  797.          window->visible = FALSE;
  798.          if (diff.defined  &&  (diff.w1 == window  ||  diff.w2 == window))
  799.             diff.defined = FALSE;
  800.          g_status.current_window = wp;
  801.          redraw_current_window( wp );
  802.          make_ruler( wp );
  803.          show_ruler( wp );
  804.       }
  805.    }
  806.    return( OK );
  807. }
  808.  
  809.  
  810. /*
  811.  * Name:    setup_window
  812.  * Purpose: To set the page length and the center line of a window, based
  813.  *           on the top and bottom lines.
  814.  * Date:    June 5, 1991
  815.  * Passed:  window: window to be set up
  816.  */
  817. void setup_window( WINDOW *window )
  818. {
  819.    window->page = window->bottom_line - (window->top_line + window->ruler) -
  820.                   g_status.overlap + 1;
  821.    if (window->page < 1)
  822.       window->page = 1;
  823. }
  824.  
  825.  
  826. /*
  827.  * Name:    finish
  828.  * Purpose: To remove the current window and terminate the program if no
  829.  *           more windows are left.
  830.  * Date:    June 5, 1991
  831.  * Passed:  window:  pointer to current window
  832.  * Notes:   Order of deciding which window becomes current window:
  833.  *          1) If any invisible window with same top and bottom line,
  834.  *          and start_col and end_col, then first invisible one becomes
  835.  *          current window.
  836.  *          2) window above if it exists becomes current window
  837.  *          3) window below if it exists becomes current window
  838.  *          4) window right if it exists becomes current window
  839.  *          5) window left  if it exists becomes current window
  840.  *          6) first available invisible window becomes current window.
  841.  *          When I added vertical windows, this routine became a LOT
  842.  *           more complicated.  To keep things reasonably sane, let's
  843.  *           only close windows that have three common edges, eg.
  844.  *
  845.  *                    ┌──────┬──────────┐
  846.  *                    │      │    no    │
  847.  *                    │      ├─────┬────┤
  848.  *                    │      │yes1 │yes1│
  849.  *                    │  no  ├─────┴────┤
  850.  *                    │      │   yes2   │
  851.  *                    │      ├──────────┤
  852.  *                    │      │   yes2   │
  853.  *                    └──────┴──────────┘
  854.  *
  855.  *          Windows with 'no' cannot be closed.  Windows with 'yes' can
  856.  *          be combined with windows that have the same yes number.
  857.  */
  858. void finish( WINDOW *window )
  859. {
  860. register WINDOW *wp;   /* for scanning other windows */
  861. register WINDOW *win;  /* register pointer for window */
  862. file_infos *file, *fp;  /* for scanning other files */
  863. int  poof;
  864. int  cline;
  865. int  top;
  866. int  bottom;
  867. int  start_col;
  868. int  end_col;
  869. int  max_letter;
  870. int  file_change = FALSE;
  871. line_list_ptr ll;
  872. line_list_ptr temp_ll;
  873.  
  874.    win = window;
  875.    entab_linebuff( );
  876.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  877.       return;
  878.  
  879.    file = win->file_info;
  880.    /*
  881.     * remove all hidden windows that point to same file
  882.     */
  883.    file = win->file_info;
  884.    for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  885.       if (wp->file_info == file) {
  886.          if (!wp->visible) {
  887.             if (wp->prev == NULL) {
  888.                if (wp->next == NULL)
  889.                   g_status.stop = TRUE;
  890.                else
  891.                   g_status.window_list = wp->next;
  892.             } else
  893.                wp->prev->next = wp->next;
  894.             if (wp->next)
  895.                wp->next->prev = wp->prev;
  896.             --wp->file_info->ref_count;
  897.             free( wp );
  898.             --g_status.window_count;
  899.          }
  900.       }
  901.    }
  902.  
  903.    if (win->prev == NULL && win->next == NULL)
  904.       g_status.stop = TRUE;
  905.  
  906.    poof = FALSE;
  907.  
  908.    if (g_status.stop != TRUE) {
  909.       /*
  910.        * see if there are any invisible windows with same top and bottom,
  911.        *  lines, and start_col and end_col as this window.  start looking at
  912.        *  end of window list.
  913.        */
  914.       top       = win->top_line;
  915.       bottom    = win->bottom_line;
  916.       start_col = win->start_col;
  917.       end_col   = win->end_col;
  918.       wp = g_status.window_list;
  919.       if (wp != NULL) {
  920.          while (wp->next != NULL)
  921.             wp = wp->next;
  922.       }
  923.       while (wp != NULL && poof == FALSE) {
  924.          if (wp->top_line == top         &&  wp->bottom_line == bottom  &&
  925.              wp->start_col == start_col  &&  wp->end_col == end_col     &&
  926.                                                               !wp->visible)
  927.             poof = TRUE;
  928.          else
  929.             wp = wp->prev;
  930.       }
  931.  
  932.       if (poof == FALSE) {
  933.          /*
  934.           * see if there are any windows above
  935.           */
  936.          wp = g_status.window_list;
  937.          while (wp != NULL && poof == FALSE) {
  938.             if (wp->bottom_line+2 == win->top_line &&
  939.                 wp->start_col     == win->start_col &&
  940.                      wp->end_col       == win->end_col   && wp->visible) {
  941.                poof = TRUE;
  942.                top  = wp->top_line;
  943.             } else
  944.                wp = wp->next;
  945.          }
  946.          if (poof == FALSE) {
  947.             /*
  948.              * see if there are any windows below
  949.              */
  950.             wp = g_status.window_list;
  951.             while (wp != NULL && poof == FALSE) {
  952.                if (wp->top_line-2 == win->bottom_line  &&
  953.                    wp->start_col     == win->start_col &&
  954.                          wp->end_col    == win->end_col   && wp->visible) {
  955.                   poof = TRUE;
  956.                   bottom = wp->bottom_line;
  957.                } else
  958.                   wp = wp->next;
  959.             }
  960.          }
  961.          if (poof == FALSE) {
  962.             /*
  963.              * see if there are any windows right
  964.              */
  965.             wp = g_status.window_list;
  966.             while (wp != NULL && poof == FALSE) {
  967.                if (wp->top_line    == win->top_line  &&
  968.                          wp->bottom_line == win->bottom_line &&
  969.                          wp->start_col-2 == win->end_col     && wp->visible) {
  970.                   poof = TRUE;
  971.                   end_col = wp->end_col;
  972.                } else
  973.                   wp = wp->next;
  974.             }
  975.          }
  976.          if (poof == FALSE) {
  977.             /*
  978.              * see if there are any windows left
  979.              */
  980.             wp = g_status.window_list;
  981.             while (wp != NULL && poof == FALSE) {
  982.                if (wp->top_line    == win->top_line  &&
  983.                    wp->bottom_line == win->bottom_line &&
  984.                    wp->end_col+2   == win->start_col   && wp->visible) {
  985.                   poof = TRUE;
  986.                   start_col = wp->start_col;
  987.                } else
  988.                   wp = wp->next;
  989.             }
  990.          }
  991.          if (poof == FALSE) {
  992.             /*
  993.              * see if there are any other invisible windows.  start looking
  994.              *  at the end of the window list.
  995.              */
  996.             wp = g_status.window_list;
  997.             if (wp != NULL) {
  998.                while (wp->next != NULL)
  999.                   wp = wp->next;
  1000.             }
  1001.             while (wp != NULL && poof == FALSE) {
  1002.                if (!wp->visible)
  1003.                   poof = TRUE;
  1004.                else
  1005.                   wp = wp->prev;
  1006.             }
  1007.          }
  1008.       }
  1009.       if (poof) {
  1010.          wp->visible = TRUE;
  1011.          cline = wp->cline - (wp->top_line+wp->ruler);
  1012.          wp->top_line = top;
  1013.          wp->bottom_line = bottom;
  1014.          wp->cline = (wp->top_line+wp->ruler) + cline;
  1015.          if (wp->cline > wp->bottom_line)
  1016.             wp->cline = wp->top_line+wp->ruler;
  1017.          wp->start_col = start_col;
  1018.          wp->end_col   = end_col;
  1019.          if (start_col == 0 && end_col == g_display.ncols - 1)
  1020.             wp->vertical = FALSE;
  1021.          else
  1022.             wp->vertical = TRUE;
  1023.          check_virtual_col( wp, wp->rcol, wp->ccol );
  1024.          setup_window( wp );
  1025.          show_window_header( wp );
  1026.          if (wp->vertical)
  1027.             show_vertical_separator( wp );
  1028.  
  1029.          /*
  1030.           * The window above, below, or previously invisible becomes the new
  1031.           *  current window.
  1032.           */
  1033.          g_status.current_window = wp;
  1034.       }
  1035.    }
  1036.  
  1037.    if (!poof && g_status.stop != TRUE)
  1038.       /*
  1039.        * cannot close current window
  1040.        */
  1041.       error( WARNING, win->bottom_line, win7 );
  1042.    else {
  1043.  
  1044.       /*
  1045.        * free unused file memory if necessary
  1046.        */
  1047.       if (--file->ref_count == 0) {
  1048.  
  1049.          /*
  1050.           * if a block is marked, unmark it
  1051.           */
  1052.          if (file == g_status.marked_file) {
  1053.             g_status.marked      = FALSE;
  1054.             g_status.marked_file = NULL;
  1055.          }
  1056.  
  1057.          for (fp=g_status.file_list; fp != NULL; fp=fp->next) {
  1058.             if (fp->file_no > file->file_no)
  1059.                fp->file_no--;
  1060.          }
  1061.          file_change = file->file_no;
  1062.  
  1063.          /*
  1064.           * no window now refers to this file, so remove file from the list
  1065.           */
  1066.          if (file->prev == NULL)
  1067.             g_status.file_list = file->next;
  1068.          else
  1069.             file->prev->next = file->next;
  1070.          if (file->next)
  1071.             file->next->prev = file->prev;
  1072.  
  1073.          /*
  1074.           * free the line pointers, linked list of line pointers, and
  1075.           *  file struc.
  1076.           */
  1077.          ll = file->undo_top;
  1078.          while (ll != NULL) {
  1079.             temp_ll = ll->next;
  1080.             if (ll->line != NULL)
  1081.                my_free( ll->line );
  1082.             my_free( ll );
  1083.             ll = temp_ll;
  1084.          }
  1085.  
  1086.          ll = file->line_list;
  1087.          while (ll != NULL) {
  1088.             temp_ll = ll->next;
  1089.             if (ll->line != NULL)
  1090.                my_free( ll->line );
  1091.             my_free( ll );
  1092.             ll = temp_ll;
  1093.          }
  1094.  
  1095. #if defined( __MSC__ )
  1096.          _fheapmin( );
  1097. #endif
  1098.  
  1099.          free( file );
  1100.          if (--g_status.file_count) {
  1101.             show_file_count( g_status.file_count );
  1102.             show_avail_mem( );
  1103.          }
  1104.       }
  1105.  
  1106.       /*
  1107.        * remove the current window from the window list
  1108.        */
  1109.       if (win->prev == NULL)
  1110.          g_status.window_list = win->next;
  1111.       else
  1112.          win->prev->next = win->next;
  1113.  
  1114.       if (win->next)
  1115.          win->next->prev = win->prev;
  1116.  
  1117.       if (diff.defined  &&  (diff.w1 == win  ||  diff.w2 == win))
  1118.          diff.defined = FALSE;
  1119.  
  1120.       /*
  1121.        * free the memory taken by the window structure
  1122.        */
  1123.       free( win );
  1124.       --g_status.window_count;
  1125.  
  1126.       if (g_status.stop == FALSE) {
  1127.          g_status.current_file = wp->file_info;
  1128.          wp->file_info->dirty = LOCAL;
  1129.          make_ruler( wp );
  1130.          show_ruler( wp );
  1131.          show_window_count( g_status.window_count );
  1132.          if (file_change) {
  1133.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next)
  1134.                if (wp->visible)
  1135.                   show_window_number_letter( wp );
  1136.          } else {
  1137.             max_letter = 'a';
  1138.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next) {
  1139.                if (wp->file_info == file && wp->letter > max_letter)
  1140.                   max_letter = wp->letter;
  1141.             }
  1142.             if (max_letter < file->next_letter - 1)
  1143.                file->next_letter = max_letter + 1;
  1144.          }
  1145.       }
  1146.    }
  1147.  
  1148.    if (g_status.stop == TRUE) {
  1149.       if (g_status.sas_defined && g_status.sas_arg < g_status.sas_argc) {
  1150.          show_avail_mem( );
  1151.          for (bottom=0; bottom <= g_display.nlines; bottom++)
  1152.             eol_clear( 0, bottom, g_display.text_color );
  1153.          bottom  = g_display.nlines;
  1154.          set_prompt( win18, bottom );
  1155.          top = getkey( );
  1156.          top = getfunc( top );
  1157.          eol_clear( 0, bottom, g_display.text_color );
  1158.          if (top == RepeatSearchAndSeize) {
  1159.             g_status.command = RepeatSearchAndSeize;
  1160.             g_status.window_list = g_status.current_window = NULL;
  1161.             if (search_and_seize( g_status.window_list ) != ERROR)
  1162.                g_status.stop = FALSE;
  1163.          }
  1164.       }
  1165.    }
  1166. }
  1167.  
  1168.  
  1169. /*
  1170.  * Name:    create_window
  1171.  * Purpose: To allocate space for a new window structure and set up some
  1172.  *           of the relevant fields.
  1173.  * Date:    June 5, 1991
  1174.  * Passed:  window: pointer to window pointer
  1175.  *          top:    the top line of the new window
  1176.  *          bottom: the bottom line of the new window
  1177.  *          start_col:  starting column of window on screen
  1178.  *          end_col:    ending column of window on screen
  1179.  *          file:   the file structure to be associated with the new window
  1180.  * Returns: OK if window could be created
  1181.  *          ERROR if out of memory
  1182.  */
  1183. int  create_window( WINDOW **window, int top, int bottom, int start_col,
  1184.                     int end_col, file_infos *file )
  1185. {
  1186. WINDOW *wp;             /* temporary variable - use it instead of **window */
  1187. register WINDOW *prev;
  1188. int  rc;                /* return code */
  1189.  
  1190.    rc = OK;
  1191.    /*
  1192.     * allocate space for new window structure
  1193.     */
  1194.    if ((*window = (WINDOW *)calloc( 1, sizeof(WINDOW) )) == NULL) {
  1195.       /*
  1196.        * out of memory
  1197.        */
  1198.       error( WARNING, g_display.nlines, main4 );
  1199.       rc = ERROR;
  1200.    } else {
  1201.  
  1202.      /*
  1203.       * set up appropriate fields
  1204.       */
  1205.       wp              = *window;
  1206.       wp->file_info   = file;
  1207.       wp->top_line    = top+1;
  1208.       wp->bottom_line = bottom;
  1209.       wp->start_col   = start_col;
  1210.       wp->end_col     = end_col;
  1211.       wp->bin_offset  = 0;
  1212.       wp->ruler       = mode.ruler;
  1213.       make_ruler( wp );
  1214.       wp->cline       = wp->top_line + wp->ruler;
  1215.       if (start_col == 0 && end_col == g_display.ncols-1)
  1216.          wp->vertical = FALSE;
  1217.       else
  1218.          wp->vertical = TRUE;
  1219.       wp->prev        = NULL;
  1220.       wp->next        = NULL;
  1221.  
  1222.       setup_window( wp );
  1223.  
  1224.       /*
  1225.        * add window into window list
  1226.        */
  1227.       prev = g_status.current_window;
  1228.       if (prev) {
  1229.          (*window)->prev = prev;
  1230.          if (prev->next)
  1231.             prev->next->prev = *window;
  1232.          (*window)->next = prev->next;
  1233.          prev->next = *window;
  1234.       }
  1235.       if (g_status.window_list == NULL)
  1236.          g_status.window_list = *window;
  1237.  
  1238.       /*
  1239.        * record that another window is referencing this file
  1240.        */
  1241.       ++file->ref_count;
  1242.       file->dirty = LOCAL;
  1243.       ++g_status.window_count;
  1244.    }
  1245.    return( rc );
  1246. }
  1247.